<template>
  <div class="map-wrapper">
    <div :id="mapId" ref="mapBox" class="map-cnt" />
  </div>
</template>
<script>
import axios from "axios";
const defaultSet = {
  mapKey: "你的高德地图key",
};
const mapIcons = {
  default: {
    url: require("@/assets/logo.png"),
    size: [32, 32],
    offset: [13, 6],
  },
};

const sysInfo = {
  sysName: "垃圾分类监管平台",
  logo: require("@/assets/logo.png"),
  // center: ['104.054062', '30.573887']
  center: [114.919376, 32.010744],
};

const mapBaseCfg = {
  search: {
    show: true,
    id: "map-search",
  },
  point: {
    offset: [0, 0],
    icon: "default",
  },
};
export default {
  name: "AMap",
  props: {
    mapId: {
      type: String,
      default: "mapss",
    },
    mapCfg: {
      type: Object,
      default() {
        return {};
      },
    },
    points: {
      type: Array,
      default() {
        return [];
      },
    },
    type: {
      type: String,
      default: "",
    },
    gridType: {
      // 当地图类型为网格时的网格类型
      type: String || Number,
      default: "",
    },
    editData: {
      type: Object,
      default() {
        return {};
      },
    },
    styles: {
      // 网格样式
      type: Object,
      default() {
        return {};
      },
    },
    mapStyle: {
      // 地图样式
      type: String,
      default: "",
    },
    imgSizeChange: {
      // 图标是否随层级缩放改变大小
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      center: {
        lng: sysInfo.center[0],
        lat: sysInfo.center[1],
      },
      mapConfig: { ...mapBaseCfg, ...this.mapCfg },
      mapData: {
        map: {}, // 地图对象
        markers: {}, // marker点集合
      },
      oprIndex: 0,
      currentMapObj: {},
      isShowDistrict: false,
      treeData: [],
      adcode: 0,
      currentLngLat: "",
      placeSearch: "",
      gridOpr: {
        0: [
          // 区域
          {
            name: "标记点",
            id: "marker",
            key: "5",
            icon: "icon-biaojidian",
          },
          {
            name: "行政区域",
            id: "district",
            key: "4",
            icon: "icon-hangzhengquyu",
          },
          {
            name: "圆形区域",
            id: "circle",
            key: "0",
            icon: "icon-hangzhengquyu",
          },
          {
            name: "矩形区域",
            id: "rectangle",
            key: "2",
            icon: "icon-duoxuan",
          },
          {
            name: "多边形区域",
            id: "polygon",
            key: "3",
            icon: "icon-duobianxing",
          },
        ],
        1: [],
        2: [
          // 路段
          {
            name: "自定义路段",
            id: "custom",
            key: "1",
            icon: "icon-daolu",
          },
          {
            name: "路段规划",
            id: "roadPlan",
            key: "7",
            icon: "icon-luduanguihua",
          },
          {
            name: "行驶轨迹规划",
            id: "tracePlan",
            key: "8",
            icon: "icon-guiji",
          },
        ],
      },
      mapOpr: [],
      isShowClear: true,
      clearTxt: "清空",
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.mapData.mapType = this.type;
      if (this.type === "grid") {
        this.clearTxt = "重绘";
        this.isShowClear = false;
      } else {
        this.clearTxt = "清空";
        this.isShowClear = true;
      }
      this.clearTxt = this.type === "grid" ? "重绘" : "清空";
      this.mapOpr = this.gridType.toString() ? this.gridOpr[this.gridType] : [];
      setTimeout(() => {
        this.mapInit();
      }, 1000);
    });
  },
  methods: {
    mapInit() {
      /* eslint-disable */
      let _this = this;
      this.map = new AMap.Map(this.mapId, {
        center: [this.center.lng, this.center.lat],
        zoom: this.mapConfig.zoom || 14,
        zooms: this.mapConfig.zooms || [3, 18],
        viewMode: this.mapConfig.viewMode || "2D",
      });
      this.mapStyle && this.map.setMapStyle(this.mapStyle);
      this.mapData.map = this.map;
      this.map.on("complete", () => {
        this.$emit("ready", this.mapData);
        this.addPoint(this.map, this.points);
        this.type !== "view" && this.createSearch();
        Object.keys(this.editData).length && this.setEditData();
      });
      if (this.type === "grid") {
        this.initMapOpr();
      }
      this.map.on("click", (e) => {
        _this.currentLngLat = e.lnglat;
        if (_this.type === "grid") {
          let item = _this.mapOpr[_this.oprIndex];
          switch (
            item.id // 画标记点
          ) {
            case "marker": {
              this.mapOprClear();
              _this.currentMapObj.overlays = _this.drawOverlay("0");
              _this.currentMapObj.oprEditor = new AMap.CircleEditor(
                _this.map,
                _this.currentMapObj.overlays
              );
              _this.currentMapObj.oprEditor.open();
              _this.getOprData();
              _this.currentMapObj.oprEditor.on("adjust", () => {
                _this.getOprData();
              });
              this.isShowClear = true;
              break;
            }
          }
        }
        if (_this.type === "choose") {
          _this.map.remove(_this.mapData.markers);
          _this.mapData.markers = [];
          _this.mapData.markers.push(
            new AMap.Marker({
              map: _this.map,
              position: _this.currentLngLat,
            })
          );
          _this.getAddress(e.lnglat.lng, e.lnglat.lat, (data) => {
            this.mapData.chooseData = {
              lng: e.lnglat.lng,
              lat: e.lnglat.lat,
              address: data,
            };
            this.$emit("getMapData", this.mapData);
          });
        }
      });
    },
    initMapOpr() {
      let _this = this;
      if (this.mapOpr.length) {
        this.currentMapObj.mouseTool = new AMap.MouseTool(_this.map);
        this.currentMapObj.overlays = [];
        this.currentMapObj.oprEditor = {};
        this.getDistrictData();
        this.currentMapObj.mouseTool.on("draw", (e) => {
          _this.currentMapObj.overlays = e.obj;
          let currentOpr = _this.mapOpr[_this.oprIndex];
          switch (
            currentOpr.key // 0 - 圆，2 - 矩形，3 - 自定义，4 - 行政围栏，1 - 线路，5-标记点'
          ) {
            case "0":
              _this.currentMapObj.oprEditor = new AMap.CircleEditor(
                _this.map,
                e.obj
              );
              break;
            case "2": {
              let rect = new AMap.Rectangle({
                map: _this.map,
                bounds: e.obj.getBounds(),
                strokeColor: _this.styles.strokeColor || "#1f86ea",
                fillColor: _this.styles.strokeColor || "#1f86ea",
                strokeWeight: _this.styles.strokeWeight || "2",
                fillOpacity: _this.styles.fillOpacity || "0.4",
              });
              _this.map.remove(_this.currentMapObj.overlays);
              _this.currentMapObj.overlays = rect;
              _this.currentMapObj.oprEditor = new AMap.RectangleEditor(
                _this.map,
                _this.currentMapObj.overlays
              );
              break;
            }
            case "3": {
              _this.currentMapObj.oprEditor = new AMap.PolyEditor(
                _this.map,
                _this.currentMapObj.overlays
              );
              break;
            }
            case "1":
              _this.currentMapObj.oprEditor = new AMap.PolyEditor(
                _this.map,
                e.obj
              );
              break;
            default:
              "";
          }
          _this.currentMapObj.oprEditor.open();
          _this.getOprData();
          _this.currentMapObj.oprEditor.on("adjust", () => {
            _this.getOprData();
          });
          _this.isShowClear = true;
          _this.currentMapObj.mouseTool.close(false);
        });
      }
    },
    addPoint(map, data) {
      if (data.length) {
        data.some((item) => {
          if (item.lng && item.lat) {
            let position = new AMap.LngLat(item.lng, item.lat),
              icon = this.getIcon(map, mapIcons[this.mapConfig.point.icon]),
              offset = item.offset
                ? new AMap.Pixel(item.offset[0], item.offset[1])
                : this.mapConfig.point.offset
                ? new AMap.Pixel(
                    this.mapConfig.point.offset[0],
                    this.mapConfig.point.offset[1]
                  )
                : new AMap.Pixel(0, 0);
            let marker = new AMap.Marker({
              position: position,
              offset: offset,
              icon: item.img || icon,
              content: item.content,
              angle: item.direction - 0 - 90,
              topWhenClick: true, //默认点击置顶
              autoRotation: true, //自动旋转res
              clickable: true,
            });
            if (item.label) {
              marker.setLabel({
                offset: new AMap.Pixel(0, 0), //设置文本标注偏移量
                content: item.label
                  ? item.label.indexOf("<") > -1
                    ? item.label
                    : `<div class="map-labels">${item.label}</div>`
                  : "",
                direction: "center", //设置文本标注方位
              });
            }
            map.add(marker);
            this.mapData.markers[item.id] = marker;
          }
        });
        this.map.setCenter(new AMap.LngLat(data[0].lng, data[0].lat));
      }
    },
    getIcon(map, data) {
      let icon = new AMap.Icon({
        image: data.url || data,
        imageOffset: data.offset
          ? new AMap.Size(data.offset[0], data.offset[1])
          : new AMap.Size(0, 0),
        size: data.size
          ? new AMap.Size(data.size[0], data.size[1])
          : new AMap.Size(80, 80),
      });
      return icon;
    },
    clearMapById(id) {
      let marker = this.mapData.markers[id];
      marker && map.remove(marker);
      delete this.mapData.markers[id];
    },
    createSearch() {
      let auto = new AMap.Autocomplete({
        input: this.mapConfig.search.id,
      });
      AMap.event.addListener(auto, "select", (e) => {
        this.map.panTo(e.poi.location);
        if (this.type === "choose") {
          this.map.remove(this.mapData.markers);
          this.mapData.markers = new AMap.Marker({
            map: this.map,
            position: e.poi.location,
          });
          this.mapData.chooseData = {
            lng: e.poi.location.lng,
            lat: e.poi.location.lat,
            address: e.poi.district + e.poi.address,
          };
          this.$emit("getMapData", this.mapData);
        }
      });
    },
    toDraw(item, index) {
      this.oprIndex = index;
      this.overlayClear();
      let color = this.styles.strokeColor || "#1f86ea",
        weight = this.styles.strokeWeight || "2";
      switch (
        item.id // 0 - 圆，2 - 矩形，3 - 自定义，4 - 行政围栏，1 - 线路，5-标记点',
      ) {
        case "district": {
          this.isShowDistrict = true;
          break;
        }
        case "circle": {
          this.currentMapObj.mouseTool.circle({
            strokeColor: color,
            strokeWeight: weight,
          });
          break;
        }
        case "rectangle": {
          this.currentMapObj.mouseTool.rectangle({
            strokeColor: color,
            strokeWeight: weight,
          });
          break;
        }
        case "polygon": {
          this.currentMapObj.mouseTool.polygon({
            strokeColor: color,
            strokeWeight: weight,
          });
          break;
        }
        case "custom": {
          this.currentMapObj.mouseTool.polyline({
            strokeColor: color,
            strokeWeight: weight,
          });
          break;
        }
        default:
          "";
      }
    },
    drawOverlay(type, data) {
      let drawObj = {},
        lngLat = [],
        params = {};
      params.map = this.map;
      params.strokeColor = this.styles.strokeColor || "#1f86ea";
      params.fillColor = this.styles.strokeColor || "#1f86ea";
      params.strokeWeight = this.styles.strokeWeight || "2";
      params.fillOpacity = this.styles.fillOpacity || "0.4";
      data = data || {};
      if (type !== "0") {
        data.lngLat.split(";").some(function (item, index) {
          lngLat[index] = new AMap.LngLat(
            item.split(",")[0],
            item.split(",")[1]
          );
        });
      }
      switch (type) {
        case "0": {
          // 圆
          lngLat = data.circle
            ? new AMap.LngLat(
                data.circle.split(",")[0],
                data.circle.split(",")[1]
              )
            : this.currentLngLat;
          params.center = lngLat;
          params.radius = data.radius || 800;
          drawObj = new AMap.Circle(params);
          break;
        }
        case "2": {
          // 矩形
          params.bounds = new AMap.Bounds(lngLat[0], lngLat[1]);
          drawObj = new AMap.Rectangle(params);
          break;
        }
        case "3": {
          // 多边形
          params.path = lngLat;
          drawObj = new AMap.Polygon(params);
          break;
        }
        case "1": {
          // 线路
          params.path = lngLat;
          drawObj = new AMap.Polyline(params);
          break;
        }
        default:
          "";
      }
      return drawObj;
    },
    drawDistrict(bounds) {
      let color = this.styles.strokeColor || "#1f86ea",
        weight = this.styles.strokeWeight || "2",
        data = [],
        _this = this;
      if (bounds.length) {
        let polygon = new AMap.Polygon({
          map: _this.map,
          strokeWeight: weight,
          path: bounds,
          fillOpacity: 0.2,
          fillColor: color,
          strokeColor: color,
        });
        let point = polygon.getPath();
        let arr = [];
        if (point.length) {
          point.some((item, index) => {
            arr[index] = item.lng + "," + item.lat;
          });
        }
        data.push(arr.join(";"));
        _this.map.setFitView(polygon); // 视口自适应
        _this.currentMapObj.overlays = polygon;
        this.isShowClear = true;
        _this.mapData.gridOpr = {
          areaType: "4",
          lngLat: data.join(";"),
        };
        this.$emit("getMapData", this.mapData);
      }
    },
    mapReset() {
      this.overlayClear();
      this.oprIndex = 0;
    },
    overlayClear() {
      this.currentMapObj.overlays &&
        Object.keys(this.currentMapObj.overlays).length &&
        this.mapData.map.remove(this.currentMapObj.overlays);
      this.currentMapObj.overlays = {};
      if (
        this.currentMapObj.oprEditor &&
        Object.keys(this.currentMapObj.oprEditor).length
      ) {
        this.currentMapObj.oprEditor.close();
      }
      this.currentMapObj.oprEditor = {};
    },
    mapOprClear() {
      if (this.type === "grid") {
        this.overlayClear();
        this.isShowClear = false;
        this.mapOpr.length &&
          this.toDraw(this.mapOpr[this.oprIndex], this.oprIndex);
      } else {
        this.placeSearch = "";
      }
    },
    getOprData() {
      let current = this.mapOpr[this.oprIndex];
      let data = {},
        center = {};
      switch (current.key) {
        case "5": {
          // 标记点
          center = this.currentMapObj.overlays.getCenter();
          data.circle = center.lng + "," + center.lat;
          data.radius = parseInt(this.currentMapObj.overlays.getRadius());
          break;
        }
        case "0": {
          // 圆
          center = this.currentMapObj.overlays.getCenter();
          data.circle = center.lng + "," + center.lat;
          data.radius = parseInt(this.currentMapObj.overlays.getRadius());
          break;
        }
        case "2": {
          // 矩形
          center = this.currentMapObj.overlays.getBounds();
          data.lngLat =
            center.northeast.lng.toFixed(6) +
            "," +
            center.northeast.lat.toFixed(6) +
            ";" +
            center.southwest.lng.toFixed(6) +
            "," +
            center.southwest.lat.toFixed(6);
          break;
        }
        case "3": {
          // 多边形
          let point = this.currentMapObj.overlays.getPath();
          let arr = [];
          if (point.length) {
            point.some((item, index) => {
              arr[index] = item.lng + "," + item.lat;
            });
          }
          data.lngLat = arr.join(";");
          break;
        }
        case "1": {
          // 线路
          let point = this.currentMapObj.overlays.getPath();
          let arr = [];
          if (point.length) {
            point.some((item, index) => {
              arr[index] = item.lng + "," + item.lat;
            });
          }
          data.lngLat = arr.join(";");
          break;
        }
        default:
          "";
      }
      data.areaType = current.key;
      this.mapData.gridOpr = data;
      this.$emit("getMapData", this.mapData);
    },
    getDistrictData() {
      axios({
        url: `https://restapi.amap.com/v3/config/district?key=${defaultSet.mapKey}&adcode=100000&keywords=$`,
        dataType: "jsonp",
        timeout: 6000,
      }).then((res) => {
        if (res.data.status === "1") {
          this.treeData = res.data.districts[0].districts;
        }
      });
    },
    toCancel() {
      this.isShowDistrict = false;
    },
    toConfirm() {
      // 画行政区域
      let _this = this;
      let district = new AMap.DistrictSearch({
        subdistrict: 0, //获取边界不需要返回下级行政区
        extensions: "all", //返回行政区边界坐标组等具体信息
        level: "province", //查询行政级别为省
      });
      district.search(this.adcode, (status, result) => {
        this.map.remove(_this.currentMapObj.overlays);
        if (status === "complete") {
          let bounds = result.districtList[0].boundaries,
            bound = [],
            maxLen = 0;
          bounds.some((item) => {
            if (item.length > maxLen) bound = item;
          });
          if (bound.length) {
            this.drawDistrict(bound);
          }
        }
      });
      this.isShowDistrict = false;
    },
    toChooseTree(selectedKeys) {
      this.adcode = selectedKeys[0];
    },
    getAddress(lng, lat, callback) {
      if (!lng && !lat) return false;
      axios({
        url: `https://restapi.amap.com/v3/geocode/regeo?key=${defaultSet.mapKey}&location=${lng},${lat}&output=JSON`,
        dataType: "jsonp",
        timeout: 6000,
      }).then((res) => {
        if (res.data.status === "1") {
          let address = res.data.regeocode.formatted_address;
          callback && callback(address);
        }
      });
    },
    setEditData() {
      // 回显地图数据
      let _this = this;
      if (this.type === "grid") {
        let tempPoint = this.editData["lngLat"] || this.editData["circle"];
        let center =
          tempPoint.indexOf(";") > -1 ? tempPoint.split(";") : [tempPoint];
        _this.map.setCenter(
          new AMap.LngLat(center[0].split(",")[0], center[0].split(",")[1])
        );
        let oprArr = this.gridOpr[this.editData.fenceType];
        if (oprArr && oprArr.length) {
          let key = this.editData.areaType;
          oprArr.some((item, index) => {
            if (item.key === key) {
              this.oprIndex = index;
            }
          });
          if (key === "4") {
            if (this.editData.lngLat) {
              let temp =
                  this.editData.lngLat.indexOf(";") > -1
                    ? this.editData.lngLat.split(";")
                    : [this.editData.lngLat],
                bounds = [];
              _this.map.setCenter(
                new AMap.LngLat(temp[0].split(",")[0], temp[0].split(",")[1])
              );
              temp.some((item, index) => {
                bounds[index] = new AMap.LngLat(
                  item.split(",")[0],
                  item.split(",")[1]
                );
              });
              this.drawDistrict(bounds);
            }
          } else {
            let type = key;
            if (key === "5") {
              type = key;
            }
            this.currentMapObj.overlays = this.drawOverlay(type, this.editData);
            switch (key) {
              case "0":
                _this.currentMapObj.oprEditor = new AMap.CircleEditor(
                  _this.map,
                  _this.currentMapObj.overlays
                );
                break;
              case "2": {
                this.currentMapObj.oprEditor = new AMap.RectangleEditor(
                  _this.map,
                  this.currentMapObj.overlays
                );
                break;
              }
              case "3":
                this.currentMapObj.oprEditor = new AMap.PolyEditor(
                  _this.map,
                  this.currentMapObj.overlays
                );
                break;
              case "1":
                this.currentMapObj.oprEditor = new AMap.PolyEditor(
                  _this.map,
                  this.currentMapObj.overlays
                );
                break;
              case "5":
                _this.currentMapObj.oprEditor = new AMap.CircleEditor(
                  _this.map,
                  _this.currentMapObj.overlays
                );
              default:
                "";
            }
            _this.currentMapObj.oprEditor.open();
            _this.getOprData();
            _this.currentMapObj.oprEditor.on("adjust", () => {
              _this.getOprData();
            });
            this.isShowClear = true;
          }
        }
      } else if (this.type === "choose" || this.type === "view") {
        if (this.editData.lngLat) {
          this.mapData.markers = [];
          this.mapData.markers.push(
            new AMap.Marker({
              map: this.map,
              position: new AMap.LngLat(
                this.editData.lngLat.split(",")[0],
                this.editData.lngLat.split(",")[1]
              ),
            })
          );
          this.map.setFitView();
        }
      }
    },
    setOverlayOpt(opt) {
      let options = {
        strokeColor: opt.strokeColor,
        strokeWeight: opt.strokeWeight,
        fillColor: opt.strokeColor,
      };
      Object.keys(options).forEach((key) => {
        if (!options[key]) delete options[key];
      });
      this.currentMapObj.overlays &&
        Object.keys(this.currentMapObj.overlays).length &&
        this.currentMapObj.overlays.setOptions(options);
    },
  },
  watch: {
    points() {
      if (!this.map) return;
      this.addPoint(this.map, this.points);
    },
    mapData: {
      handler: function (val) {
        this.$emit("getMapData", val);
      },
      immediate: true,
    },
    gridType(val) {
      if (val.toString()) {
        this.mapOpr = this.gridOpr[val];
        this.mapOpr.length &&
          this.toDraw(this.mapOpr[this.oprIndex], this.oprIndex);
      }
    },
  },
};
</script>
<style scoped>
.map-wrapper {
  width: 600px;
  height: 400px;
}
.map-cnt {
  width: 600px;
  height: 400px;
}
</style>